package bhz.netty.runtime;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.ReadTimeoutHandler;

import java.util.concurrent.TimeUnit;


/**
 * Best Do It
 */
public class Client {
	
	private static class SingletonHolder {
		static final Client instance = new Client();
	}
	
	public static Client getInstance(){
		return SingletonHolder.instance;
	}
	
	private EventLoopGroup group;
	private Bootstrap b;
	private ChannelFuture cf ;
	
	private Client(){
			group = new NioEventLoopGroup();
			b = new Bootstrap();
			b.group(group)
			 .channel(NioSocketChannel.class)
			 .handler(new LoggingHandler(LogLevel.INFO))
			 .handler(new ChannelInitializer<SocketChannel>() {
					@Override
					protected void initChannel(SocketChannel sc) throws Exception {
						sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingDecoder());
						sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingEncoder());
						//超时handler（当服务器端与客户端在指定时间以上没有任何进行通信，则会关闭响应的通道，主要为减小服务端资源占用）
						sc.pipeline().addLast(new ReadTimeoutHandler(5)); 
						sc.pipeline().addLast(new ClientHandler());
					}
		    });
	}
	
	public void connect(){
		try {
			this.cf = b.connect("127.0.0.1", 8765).sync();
			System.out.println("远程服务器已经连接, 可以进行数据交换..");				
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public ChannelFuture getChannelFuture(){
		
		if(this.cf == null){
			this.connect();
		}
		if(!this.cf.channel().isActive()){
			this.connect();
		}
		
		return this.cf;
	}
	
	public static void main(String[] args) throws Exception{
//		如果是springweb项目中进行数据同步，这里需要在监听器中进行创建实例
		
		final Client c = Client.getInstance();
//     然后再service 获取futurechannle进行发送数据，
		
//		然后再spring工厂销毁 的方法中中进行 close    
		
		
//		如果在非web项目中，应该先创 启动一个channel组，然后进行用一个线程永不退出去执行推送数据。 
		
		
		/**
		 * java 条件变量：设计， 
		 * 1，自己有一个发送队列 ， queue， 
		 * 2，然后在队列没有数据的时候，让线程进入自己的 睡眠队列。
		 * 3，一旦在有数据的情况下，立即启动线程，进行    c.getChannelFuture.
		 *     	 就算是服务器那端断开连接。也进行了重连机制.  如果是没有数据的话,服务器那端和这段超时时间之后断开连接,也没什么.不会消耗资源
		 *     
		 *     另外重点强调的一点就是：  client  只有两种状态，    1， 连接  
		 *     												   2， 断开连接后， netty就自动结束了，如果没有线程阻塞保持者
		 *     												以便于下次在此或得连接的时候，就是结束，否则的话，就是可以进行重连的。
		 *     												所以我们只要保持一个线程可以进行重连就行了.
		 */
		
		
		
//		
	final	ChannelFuture cf = c.getChannelFuture();
//		for(int i = 1; i <= 3; i++ ){
//			Request request = new Request();
//			request.setId("" + i);
//			request.setName("pro" + i);
//			request.setRequestMessage("数据信息" + i);
//			cf.channel().writeAndFlush(request);
//			TimeUnit.SECONDS.sleep(4);
//		}
//
//		cf.channel().closeFuture().sync();
//		
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				 
					System.out.println("进入子线程...");
					System.out.println(cf.channel().isActive());
					System.out.println(cf.channel().isOpen());
					
					//再次发送数据
					Request request = new Request();
					request.setId("" + 4);
					request.setName("pro" + 4);
					request.setRequestMessage("数据信息" + 4);
					cf.channel().writeAndFlush(request);					
					
					System.out.println("子线程结束.");
				 
			}
		}).start();
		cf.channel().closeFuture().sync();
		System.out.println("断开连接,主线程结束..");
		
	}
	
	
	
}
